<?php

namespace pay\libs;

use phpDocumentor\Reflection\Types\Self_;
use Yii;
use yii\log\FileTarget;

/*** 微信支付类
 * Class WxPay
 * @package common\libs
 */

class WxPay
{
    private static $appid = '';
    private static $mch_id = '';
    private static $key = '';
    private static $appSecret = '';
    private static $cookie = null;
    private static $app_notify_url = 'http://paycentre.horsevision.cn/frontend/pay-callback/call-back-url';


    public function __construct($appid,$appSecret,$mch_id,$key)
    {
        $this::$appid = $appid;
        $this::$appSecret = $appSecret;
        $this::$mch_id = $mch_id;
        $this::$key = $key;
    }



    /*** JSAPI微信支付
     * @param $notify_url       支付回调地址
     * @param $openid           用户openid
     * @param $order_sn         订单号
     * @param $total_fee        支付金额
     * @param string $body      订单描述
     * @param string $attach    附加数据
     * @return bool|mixed
     */
    public function unifiedorder($openid,$order_sn,$total_fee,$body = '', $notify_url)
    {
        $device_info = "1000";
        $nonce_str = self::createSn();
        $param = array(
            "appid" => self::$appid,//小程序ID
            "mch_id" => self::$mch_id,//商户号

//            "device_info" => $device_info,//设备号
            "nonce_str" => $nonce_str,//随机字符串
            // "sign" => $sign,//签名-----------
            "body" => $body,//商品描述
            // "detail" => "",//商品详情
            "attach" => $notify_url,//附加数据 商户回调地址
            "out_trade_no" => $order_sn,//商户订单号
            "total_fee" => $total_fee,//标价金额
//            "spbill_create_ip" => Yii::$app->request->userIP,//终端IP
            // "goods_tag" => "",//订单优惠标记
            "notify_url" => self::$app_notify_url,//通知地址
            "trade_type" => "JSAPI",//交易类型
            // "product_id" => "",//商品ID
            "openid" => $openid,//用户标识
        );
        $param["sign"] = self::computeSign($param);
        $this->recordLogin(10000101,'支付参数',json_encode($param));
        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        $res = self::curl($url, self::arrayToXml($param));
        $package = self::FromXml($res);
        if ($package['return_code'] == 'SUCCESS' and $package['result_code'] == "SUCCESS"){
            $params = [
                'appId' => self::$appid,
                'timeStamp' => time(),
                'nonceStr' => self::createSn(),
                'package' => 'prepay_id='.$package['prepay_id'],
                'signType' => 'MD5',
            ];
            $params['paySign'] = self::computeSign($params);
            return $params;
        }elseif($package['return_code'] == 'SUCCESS' and $package['result_code'] != "SUCCESS"){
            return $package['err_code_des'];
        }else{
            return $package['return_msg'];

        }

    }


    /*** NATIVE,微信支付
     * @param $notify_url           回调地址
     * @param $order_sn             订单号
     * @param $total_fee            支付金额
     * @param string $body          订单描述
     * @return bool|mixed
     */
    public function unifiedorderNative($notify_url,$order_sn,$total_fee,$body = '')
    {
        $device_info = "1000";
        $nonce_str = self::createSn();
        $param = array(
            "appid" => self::$appid,//小程序ID
            "mch_id" => self::$mch_id,//商户号

            "device_info" => $device_info,//设备号
            "nonce_str" => $nonce_str,//随机字符串
            // "sign" => $sign,//签名-----------
            "body" => $body,//商品描述
            // "detail" => "",//商品详情
//            "attach" => $attach,//附加数据
            "out_trade_no" => $order_sn,//商户订单号
            "total_fee" => $total_fee,//标价金额
            "spbill_create_ip" => Yii::$app->request->userIP,//终端IP
            // "goods_tag" => "",//订单优惠标记
            "notify_url" => $notify_url,//通知地址
            "trade_type" => "NATIVE",//交易类型
            // "product_id" => "",//商品ID
        );

//        var_dump($param);die;
        $param["sign"] = self::computeSign($param);
        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        $res = self::curl($url, self::arrayToXml($param));
        return self::FromXml($res);
    }


    /*** 发送红包
     * @param $mch_billno           订单号
     * @param $openid               openid
     * @param $total_amount         金额
     * @param $information          红包展示信息
     * @return bool|mixed
     */
    private function sendredpack($mch_billno,$openid,$total_amount,$information)
    {
        $nonce_str = self::createSn();
        $parment = [
            'wxappid' => self::$appid,
            'nonce_str' => $nonce_str,          // 随机字符串
            'mch_billno' => $mch_billno,        //订单号
            'mch_id' => self::$mch_id,
            'send_name' => $information['name'],    // 红包标题
            're_openid' => $openid,                 // openid
            'total_amount' => $total_amount,        // 红包金额
            'total_num' => 1,                       // 红包发放总人数
            'wishing' => '恭喜您,获得申港证券红包',     // 红包祝福语
            'client_ip' => Yii::$app->request->userIP,
            'act_name' => '答题赢红包',              // 活动名称
            'remark' => '快邀请好友一起答题赢红包',     // 备注
        ];

        $sign = self::computeSign($parment);
        $parment['sign'] = $sign;
        $parment = self::arrayToXml($parment);
        $url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack";

        $res = self::postXmlCurl($parment,$url,true);
        return $res;
    }






    /*
    产生唯一字符串
    $length        长度
    */
    private static  function createSn($length = 30)
    {
        $characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789123456789';
        $randomString = '';
        for ($i = 0; $i < $length; $i++) {
            $randomString .= $characters[rand(0, strlen($characters) - 1)];
        }
        return $randomString;
    }



    /*
    计算签名
    $param      参数
    $sign       返回值
    */
    private static  function computeSign($param)
    {
        $sign = '';
        if ($param) {
            ksort($param, SORT_STRING);
            foreach ($param as $k => $v) {
                $sign .= $k . "=" . $v . "&";
            }
            $sign = $sign . "key=" . self::$key;
            // echo $sign;
            $sign = md5($sign);
            $sign = strtoupper($sign);
        }
        return $sign;
    }


    /*xml转JSON*/
    private static function FromXml($xml)
    {
        if (!$xml) {
            return false;
        }
        //将XML转为array
        //禁止引用外部xml实体
        libxml_disable_entity_loader(true);

        return json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
    }



    /*数组转XML*/
    private static function arrayToXml($data)
    {
        if (!is_array($data) || count($data) <= 0) {
            return false;
        }
        $xml = "<xml>";
        foreach ($data as $key => $val) {
            if (is_numeric($val)) {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            } else {
                $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
            }
        }
        $xml .= "</xml>";
        return $xml;
    }


    public static function postXmlCurl($xml, $url, $useCert = false, $second = 30)
    {
//    $weixin_info = \Yii::$app->params['weixin'];
        $ch = curl_init();
        //设置超时
        curl_setopt($ch, CURLOPT_TIMEOUT, $second);

        //如果有配置代理这里就设置代理
//    if ($weixin_info['CURL_PROXY_HOST'] != '0.0.0.0' && $weixin_info['CURL_PROXY_PORT'] != 0) {
//      curl_setopt($ch, CURLOPT_PROXY, $weixin_info['CURL_PROXY_HOST']);
//      curl_setopt($ch, CURLOPT_PROXYPORT, $weixin_info['CURL_PROXY_PORT']);
//    }
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); //严格校验
        //设置header
        curl_setopt($ch, CURLOPT_HEADER, false);
        //要求结果为字符串且输出到屏幕上
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        if ($useCert == true) {
            //设置证书
            //使用证书：cert 与 key 分别属于两个.pem文件
            curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
            curl_setopt($ch, CURLOPT_SSLCERT, Yii::$app->getBasePath() ."/web/uploads/file/php/20190723/certificate.pem"); //'/www/wwwroot/jlbwx.cnkly.com/jlbwx/web/cert/apiclient_cert.pem'
            curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');
            curl_setopt($ch, CURLOPT_SSLKEY, Yii::$app->getBasePath() ."/web/uploads/file/php/20190723/key.pem");//'/www/wwwroot/jlbwx.cnkly.com/jlbwx/web/cert/apiclient_key.pem'
        }
        //post提交方式
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
        //运行curl
        $data = curl_exec($ch);
        //返回结果
        if ($data) {
            curl_close($ch);

            return $data;
        } else {
            $error = curl_errno($ch);
            var_dump($error);
            curl_close($ch);

            return false;
            //throw new \WxPayException("curl出错，错误码:$error");
        }
    }



    public static function curl($url, $param, $method = 'post')
    {
        $calculate_time1 = microtime(true);
        // 初始华
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_HEADER, 0);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl, CURLOPT_CERTINFO, true);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        //curl_setopt($curl, CURLOPT_VERBOSE, true); //打印日志

        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);//函数中加入下面这条语句

        if (isset(\Yii::$app->params['curl']) && isset(\Yii::$app->params['curl']['timeout'])) {
            curl_setopt($curl, CURLOPT_TIMEOUT, \Yii::$app->params['curl']['timeout']);
        } else {
            curl_setopt($curl, CURLOPT_TIMEOUT, 300);
        }

        if (array_key_exists("HTTP_USER_AGENT", $_SERVER)) {
            curl_setopt($curl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
        }

        if ( ! empty(self::$headers)) {
            $headerArr = [];
            foreach (self::$headers as $n => $v) {
                $headerArr[] = $n . ': ' . $v;
            }
            curl_setopt($curl, CURLOPT_HTTPHEADER, $headerArr);  //构造IP
        }

        if (self::$cookie) {
            curl_setopt($curl, CURLOPT_COOKIE, self::$cookie);
        }


        // post处理
        if ($method == 'post') {
            curl_setopt($curl, CURLOPT_POST, true);
            if (is_array($param)) {
                $param = http_build_query($param);
            }

            curl_setopt($curl, CURLOPT_POSTFIELDS, $param);
        } else {
            curl_setopt($curl, CURLOPT_POST, false);
        }

        // 执行输出
        $info = curl_exec($curl);
//        log
        $_errno = curl_errno($curl);
        $_error = '';
        if ($_errno) {
            $_error = curl_error($curl);
        }
        curl_close($curl);
        $calculate_time_span = microtime(true) - $calculate_time1;
//        $log = \Yii::$app->getRuntimePath() . DIRECTORY_SEPARATOR . 'curl'.time().'.log';
//        file_put_contents($log, date('Y-m-d H:i:s') . " [ time:{$calculate_time_span} ] url: {$url} \nmethod: {$method} \ndata: " . json_encode($param) . " \nresult: {$info} \nerrorno: {$_errno} error: {$_error} \n", FILE_APPEND);
        if ($_error) {
            return self::_err($_error);
        }

        return $info;
    }


    protected function recordLogin($code,$msg,$data)
    {
        $log = new FileTarget();
        $log->logFile = Yii::$app->getRuntimePath() . '/payWx/pay_' . date('Ymd') . '.log';
        $log->messages[] = [
            "[url:{$_SERVER['REQUEST_URI']}],[data:{$code},{$msg},{$data}]",
            1,
            'application',
            time(),
        ];
        $log->export();
    }



}